package com.moonciki.multids.multi;

import com.moonciki.multids.properties.DataSourceProperty;
import com.moonciki.multids.properties.MultiDataSourceProperty;
import com.moonciki.multids.util.MultiSpringBeanUtil;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源注册;
 */
@Slf4j
@Deprecated
//@Component
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private ConversionService conversionService = new DefaultConversionService();

    private PropertyValues dataSourcePropertyValues;

    // 默认数据源

    private DataSource defaultDataSource;

    private Map<String, DataSource> customDataSources = new HashMap<String, DataSource>();


    @Autowired
    private MultiDataSourceProperty multiDataSourceProperty;


    /**
     * 加载多数据源配置
     */
    @Override
    public void setEnvironment(Environment environment) {

        initDefaultDataSource();

        initCustomDataSources();

    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        System.out.println("DynamicDataSourceRegister.registerBeanDefinitions()");

        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();

        // 将主数据源添加到更多数据源中

        targetDataSources.put("dataSource", defaultDataSource);

        DynamicDataSourceContextHolder.dataSourceSet.add("dataSource");

        // 添加更多数据源

        targetDataSources.putAll(customDataSources);

        for (String key : customDataSources.keySet()) {

            DynamicDataSourceContextHolder.dataSourceSet.add(key);

        }

        // 创建DynamicDataSource

        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();

        beanDefinition.setBeanClass(DynamicDataSource.class);

        beanDefinition.setSynthetic(true);

        MutablePropertyValues mpv = beanDefinition.getPropertyValues();

        //添加属性：AbstractRoutingDataSource.defaultTargetDataSource

        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);

        mpv.addPropertyValue("targetDataSources", targetDataSources);

        registry.registerBeanDefinition("dataSource", beanDefinition);

    }

    /**
     * 加载默认数据源配置.
     */
    public void initDefaultDataSource() {
        //虚假的数据源，以便没有设置时报错
        this.defaultDataSource = new FakeDataSource();

    }

    private Map<String, Object> createDataSourcePropMap(DataSourceProperty dataSourceProperty) {
        Map<String, Object> propMap = new HashMap<>();

        propMap.put("jdbcUrl", dataSourceProperty.getJdbcUrl());
        propMap.put("maximumPoolSize", dataSourceProperty.getMaximumPoolSize());
        propMap.put("username", dataSourceProperty.getUsername());
        propMap.put("password", dataSourceProperty.getPassword());

        return propMap;
    }


    private void dynamicDataSourceInit(DynamicDataSource dynamicDataSource) {

        Map<Object, Object> targetMap = new HashMap<>();

        Map<String, DataSourceProperty> dataSourceMap = multiDataSourceProperty.getDatasources();

        if(MapUtils.isNotEmpty(dataSourceMap)){
            for(Map.Entry<String, DataSourceProperty> dataSourceEntry : dataSourceMap.entrySet()){
                String dbName = dataSourceEntry.getKey();
                DataSourceProperty dataSourceProperty = dataSourceEntry.getValue();

                String beanName = DynamicDataSourceContextHolder.getDataSourceKey(dbName);

                Map<String, Object> propMap = createDataSourcePropMap(dataSourceProperty);

                MultiSpringBeanUtil.addBean(HikariDataSource.class, beanName, propMap, "close");

                HikariDataSource dataSource = MultiSpringBeanUtil.getBean(beanName, HikariDataSource.class);

                targetMap.put(beanName, dataSource);
                DynamicDataSourceContextHolder.dataSourceSet.add(beanName);

                log.info("    --- Regist_datasource : {} ", beanName);

            }
        }

        dynamicDataSource.setTargetDataSources(targetMap);
        //一定要加，否则无法获取connection
        dynamicDataSource.afterPropertiesSet();

        log.info("DBSource init successed ...");

    }


    public void initCustomDataSources() {

        Map<String, DataSourceProperty> dataSourceMap = multiDataSourceProperty.getDatasources();

        if(MapUtils.isNotEmpty(dataSourceMap)){
            for(Map.Entry<String, DataSourceProperty> dataSourceEntry : dataSourceMap.entrySet()){

                String dbName = dataSourceEntry.getKey();
                DataSourceProperty oneDbSource = dataSourceEntry.getValue();

                String beanName = DynamicDataSourceContextHolder.getDataSourceKey(dbName);

                Map<String, Object> propMap = createDataSourcePropMap(oneDbSource);

                MultiSpringBeanUtil.addBean(HikariDataSource.class, beanName, propMap, "close");

                HikariDataSource dataSource = MultiSpringBeanUtil.getBean(beanName, HikariDataSource.class);

                customDataSources.put(dbName, dataSource);
            }
        }
    }



    /**

     * 创建datasource.

     * @param dsMap

     * @return

     */

    @SuppressWarnings("unchecked")

    public DataSource buildDataSource(Map<String, Object> dsMap) {

        Object type = dsMap.get("type");

        Class<? extends DataSource> dataSourceType;



        try {

            dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);

            String driverClassName = dsMap.get("driverClassName").toString();

            String url = dsMap.get("url").toString();

            String username = dsMap.get("username").toString();

            String password = dsMap.get("password").toString();

            DataSourceBuilder factory =   DataSourceBuilder.create().driverClassName(driverClassName).url(url).username(username).password(password).type(dataSourceType);

            return factory.build();

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

        return null;
    }



    /**

     * 为DataSource绑定更多数据

     * @param dataSource

     * @param env

     */

    private void dataBinder(DataSource dataSource, Environment env){
        /*
        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);

        dataBinder.setConversionService(conversionService);

        dataBinder.setIgnoreNestedProperties(false);//false

        dataBinder.setIgnoreInvalidFields(false);//false

        dataBinder.setIgnoreUnknownFields(true);//true



        if(dataSourcePropertyValues == null){

            Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");

            Map<String, Object> values = new HashMap<>(rpr);

            // 排除已经设置的属性

            values.remove("type");

            values.remove("driverClassName");

            values.remove("url");

            values.remove("username");

            values.remove("password");

            dataSourcePropertyValues = new MutablePropertyValues(values);

        }

        dataBinder.bind(dataSourcePropertyValues);

*/

    }



}
